# -*- coding: utf-8 -*-
# created on 2017/01/05
#

from mathsolver.functions.base import *
from mathsolver.functions.base.base import new_latex
from sympy import acos, Abs
from mathsolver.functions.process import ProcessExpression
from mathsolver.functions.mathematica.mathematicaSolve import MathematicaSolve, MathematicaSimplify
from mathsolver.functions.xiangliang.basic import (XLJiHeConditionEqTransform, xl_search_multiple, XLJudgeAxis,
                                                   XLXiangs, XLAxisConditionEqTransform, XLJiHeConditionExprTransform,
                                                   xl_solutions_subs, VectorAbsKnownUpdate, VectorAxisKnownUpdate)
from mathsolver.functions.xiangliang.Vector_Fundamental import vector_axis_names, vector_get_abs, vector_get_angles


# 向量法：向量夹角：不含equations
class XLGetAngle001(BaseFunction):
    """
    若向量\\overrightarrow a =({1,2}),\\overrightarrow b=({1,-1}),
    则2\\overrightarrow a + \\overrightarrow b 与\\overrightarrow a - \\overrightarrow b的夹角等于 ()
    """

    def solver(self, *args):
        assert len(args) == 2
        known = self.known
        if 'Vequations' in known:
            veqs = known['Vequations']
            assert not veqs
        vector_a = args[0]
        vector_b = args[1]
        flag = XLJudgeAxis(known).solver(vector_a, vector_b).output[0].sympify()
        assert flag
        vectors = XLXiangs(known).solver(vector_a, vector_b).output[0].sympify()
        vectors_axis_names = vector_axis_names(vectors)
        stepsoler = VectorAxisKnownUpdate(known).solver(vectors_axis_names)
        self.steps += stepsoler.steps
        new_known = stepsoler.output[0]
        cos_angle = vector_a * vector_b / (Abs(vector_a) * Abs(vector_b))
        new_cos_angle = ProcessExpression(known=new_known).solver(BaseValue(str(cos_angle))).output[0].sympify()
        new_cos = acos(new_cos_angle)
        new_cos = MathematicaSimplify().solver(BasePoly(new_cos)).output[0].sympify()
        self.steps.append(["", "由向量的夹角公式，得"])
        self.steps.append(["", "∴%s和%s的夹角为: %s" % (new_latex(vector_a), new_latex(vector_b), new_latex(new_cos))])
        self.output.append(BaseNumbers([new_cos]))
        self.label.add("向量夹角-坐标法")
        return self


class XLGetAngle002(BaseFunction):
    """
    平面向量\\overrightarrow{a},\\overrightarrow{b},已知\\overrightarrow{a}=(4,3),2\\overrightarrow{a}+\\overrightarrow{b}=(3,18),
    则\\overrightarrow{a},\\overrightarrow{b}夹角的余弦值等于()
    """

    def solver(self, *args):
        assert len(args) == 2
        known = self.known
        assert 'Vequations' in known
        veqs = known['Vequations']
        assert veqs
        vector_a = args[0]
        vector_b = args[1]
        flag = XLJudgeAxis(known).solver(vector_a, vector_b).output[0].sympify()
        assert flag
        vectors = XLXiangs(known).solver(vector_a, vector_b).output[0].sympify()
        vectors_axis_names = vector_axis_names(vectors)
        stepsoler = VectorAxisKnownUpdate(known).solver(vectors_axis_names)
        self.steps += stepsoler.steps
        new_known = stepsoler.output[0]
        condition_veqs = []
        for eq in veqs:
            new_eqs = XLAxisConditionEqTransform(new_known).solver(BaseEq(eq)).output[0].sympify()
            for new_eq in new_eqs:
                condition_veqs.append(new_eq)
        self.steps.append(["", "依题意，得"])
        if len(condition_veqs) == 1:
            self.steps.append(["", "%s" % BaseEq(condition_veqs[0]).printing()])
        else:
            self.steps.append(["", "%s" % BaseIneqs(condition_veqs).printing()])
        solutions = MathematicaSolve().solver(BaseIneqs(condition_veqs)).output[0]
        self.steps.append(["", "解得: %s" % solutions.printing()])
        self.steps.append(["", "由向量的夹角公式，得"])
        cos_angle = vector_a * vector_b / (Abs(vector_a) * Abs(vector_b))
        new_cos_angle = ProcessExpression(new_known).solver(BaseValue(str(cos_angle))).output[0].sympify()
        answers = xl_search_multiple(solutions.sympify(), new_cos_angle)
        assert answers
        target_values = []
        for ans in answers:
            new_value = new_cos_angle
            new_value = new_value.subs(ans)
            new_value = acos(new_value)
            if len(str(new_value)) > 15:
                new_value = MathematicaSimplify().solver(BasePoly(new_value)).output[0].sympify()
            target_values.append(new_value)
        target_values = set(target_values)
        target_values = list(target_values)
        self.steps.append(["", "∴ %s" % " 或 ".join(
            ["%s和%s的夹角为: %s" % (new_latex(vector_a), new_latex(vector_b), new_latex(v)) for v in target_values])])
        self.output.append(BaseNumbers(target_values))
        self.label.add("向量夹角-坐标法")
        return self


# 几何法：向量夹角：equations无解
class XLGetAngle003(BaseFunction):
    """
    若向量\\overrightarrow{a},\\overrightarrow{b}的夹角为\\frac{π}{3},|\\overrightarrow{a}| = 2,|\\overrightarrow{b}| = 1.
    则\\overrightarrow{a}与\\overrightarrow{a} + 2\\overrightarrow{b}的夹角为( )
    """

    def solver(self, *args):
        assert len(args) == 2
        known = self.known
        assert 'Vequations' in known
        veqs = known['Vequations']
        assert veqs
        vector_a = args[0]
        vector_b = args[1]
        flag = XLJudgeAxis(known).solver(vector_a, vector_b).output[0].sympify()
        assert not flag
        vectors = XLXiangs(known).solver(vector_a, vector_b).output[0].sympify()
        stepsolver = VectorAbsKnownUpdate(known).solver(vectors)
        self.steps += stepsolver.steps
        condition_veqs = []
        abs_symbols = []
        c_angle_symbols = []
        for eq in veqs:
            new_eq = XLJiHeConditionEqTransform(known).solver(BaseEq(eq)).output[0].sympify()
            condition_veqs.append(new_eq)
            expr = new_eq[0] - new_eq[1]
            expr_abss = vector_get_abs(expr)
            if expr_abss:
                for expr_Abs in expr_abss:
                    abs_symbols.append(expr_Abs)
            expr_c_angles = vector_get_angles(expr)
            if expr_c_angles:
                for expr_CAngle in expr_c_angles:
                    c_angle_symbols.append(expr_CAngle)
        abs_symbols = set(abs_symbols)
        abs_symbols = list(abs_symbols)
        if abs_symbols:
            for Abs_symbol in abs_symbols:
                condition_veqs.append([Abs_symbol, '>=', S.Zero])
        c_angle_symbols = set(c_angle_symbols)
        c_angle_symbols = list(c_angle_symbols)
        if c_angle_symbols:
            for CAngle_symbol in c_angle_symbols:
                condition_veqs.append([CAngle_symbol, '>=', -1])
                condition_veqs.append([CAngle_symbol, '<=', 1])
        if len(condition_veqs) == 1:
            self.steps.append(["", "%s" % BaseEq(condition_veqs[0]).printing()])
        else:
            self.steps.append(["", "%s" % BaseIneqs(condition_veqs).printing()])
        solutions = MathematicaSolve().solver(BaseIneqs(condition_veqs)).output[0].sympify()
        assert solutions.__class__.__name__ == "BooleanTrue"
        self.steps.append(["", "由向量的夹角公式，得"])
        cos_angle = vector_a * vector_b / (Abs(vector_a) * Abs(vector_b))
        new_cos_angle = XLJiHeConditionExprTransform(known).solver(BasePoly(cos_angle)).output[0].sympify()
        new_angle = acos(new_cos_angle)
        self.steps.append(
            ["", "∴ %s与%s的夹角为: %s" % (new_latex(vector_a), new_latex(vector_b), new_latex(new_angle))])
        self.output.append(BaseNumbers([new_angle]))
        self.label.add("向量夹角-几何法")
        return self


# 几何法：向量夹角：equations有解

class XLGetAngle004(BaseFunction):
    """
    已知向量\\overrightarrow{a}、\\overrightarrow{b}满足|\\overrightarrow{a}|=1,|\\overrightarrow{b}|=4,\\overrightarrow{a}•\\overrightarrow{b}=2,则\\overrightarrow{a}与\\overrightarrow{b}夹角为()
    """

    def solver(self, *args):
        assert len(args) == 2
        known = self.known
        assert 'Vequations' in known
        veqs = known['Vequations']
        assert veqs
        vector_a = args[0]
        vector_b = args[1]
        flag = XLJudgeAxis(known).solver(vector_a, vector_b).output[0].sympify()
        assert not flag
        vectors = XLXiangs(known).solver(vector_a, vector_b).output[0].sympify()
        stepsolver = VectorAbsKnownUpdate(known).solver(vectors)
        self.steps += stepsolver.steps
        condition_veqs = []
        abs_symbols = []
        c_angle_symbols = []
        for eq in veqs:
            if len(eq) == 2:
                new_eq = XLJiHeConditionEqTransform(known).solver(BaseEq(eq)).output[0].sympify()
            else:
                new_eq = XLJiHeConditionEqTransform(known).solver(BaseIneq(eq)).output[0].sympify()
            condition_veqs.append(new_eq)
            if len(new_eq) == 2:
                expr = new_eq[0] - new_eq[1]
            else:
                expr = new_eq[0] - new_eq[2]
            expr_abss = vector_get_abs(expr)
            if expr_abss:
                for expr_Abs in expr_abss:
                    abs_symbols.append(expr_Abs)
            expr_c_angles = vector_get_angles(expr)
            if expr_c_angles:
                for expr_CAngle in expr_c_angles:
                    c_angle_symbols.append(expr_CAngle)
        abs_symbols = set(abs_symbols)
        abs_symbols = list(abs_symbols)
        if abs_symbols:
            for Abs_symbol in abs_symbols:
                condition_veqs.append([Abs_symbol, '>=', S.Zero])
        c_angle_symbols = set(c_angle_symbols)
        c_angle_symbols = list(c_angle_symbols)
        if c_angle_symbols:
            for CAngle_symbol in c_angle_symbols:
                condition_veqs.append([CAngle_symbol, '>=', -1])
                condition_veqs.append([CAngle_symbol, '<=', 1])
        self.steps.append(["", "依题意，得"])
        if len(condition_veqs) == 1:
            self.steps.append(["", "%s" % BaseEq(condition_veqs[0]).printing()])
        else:
            self.steps.append(["", "%s" % BaseIneqs(condition_veqs).printing()])
        solutions = MathematicaSolve().solver(BaseIneqs(condition_veqs)).output[0]
        assert solutions.sympify()
        self.steps.append(["", "解得: %s" % (solutions.printing())])
        self.steps.append(["", "由向量的夹角公式，得"])
        cos_angle = vector_a * vector_b / (Abs(vector_a) * Abs(vector_b))
        new_cos_angle = XLJiHeConditionExprTransform(known).solver(BasePoly(cos_angle)).output[0].sympify()
        target_values = xl_solutions_subs(solutions, new_cos_angle)
        angle_values = []
        for target_value in target_values:
            new_value = acos(target_value)
            if len(str(new_value)) < 15:
                new_value = new_value.expand().simplify()
            else:
                new_value = MathematicaSimplify().solver(BasePoly(new_value)).output[0].sympify()
            angle_values.append(new_value)
        angle_values = set(angle_values)
        angle_values = list(angle_values)
        self.steps.append(["", "∴ %s" % " 或 ".join(
            ["%s和%s的夹角为: %s" % (new_latex(vector_a), new_latex(vector_b), new_latex(v)) for v in angle_values])])
        self.output.append(BaseNumbers(angle_values))
        self.label.add("向量夹角-几何法")
        return self


# 求向量的夹角


class XLGetAngle(BaseFunction):
    CLS = [XLGetAngle001, XLGetAngle002, XLGetAngle003, XLGetAngle004]

    def solver(self, *args):
        known = self.known
        if len(args) == 1:
            values = args[0].value
            vector_a = sympify(values[0])
            vector_b = sympify(values[1])
        else:
            vector_a = sympify(args[0].value)
            vector_b = sympify(args[1].value)
        r = None
        for cl in XLGetAngle.CLS:
            try:
                new_known = dict(known)
                r = cl(new_known, verbose=True).solver(vector_a, vector_b)
                break
            except Exception:
                pass
        if not r:
            raise 'try fail'
        return r


if __name__ == '__main__':
    pass
